#!/usr/bin/python2.5
"""
    Googbus Calendar - Uses Googbus and provides calendar UI to Google
    Calendar.
    
    Copyright (C) 2008  Matti Raty

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/.
"""
import hildon
import gtk
import dbus
import datetime
import gobject
import osso
import locale

from googbus import googdefs
from googbus_calendar_dlgs import UserAccountDlg
from googbus_calendar_dlgs import AddNewEventDlg

class GoogbusCalendarApp(hildon.Program):
    
    """
    Weekday names for datetime.weekday
    """
    WEEKDAYS = ("Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday")

    
    def __init__(self):
        hildon.Program.__init__(self)
        
        self.osso_context = osso.Context("googbus_calendar", "0.1.0", False)
        
        self.wnd = hildon.Window()
        
        self.wnd.set_title("Googbus Calendar")
        gtk.set_application_name("")
        
        self.wnd.connect("destroy", gtk.main_quit)
        
        self.create_toolbar()
        self.scrolledwnd = gtk.ScrolledWindow()
        self.scrolledwnd.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
        self.wnd.add(self.scrolledwnd)
        
        #Locale settings for formatting date and time
        locale.setlocale(locale.LC_ALL, '')
            
        self.LOCALE_TIME = locale.nl_langinfo(locale.T_FMT)
        self.LOCALE_DATE = locale.nl_langinfo(locale.D_FMT)

        self.idle = gobject.idle_add(self.fetch_events)

        self.add_window(self.wnd)
        
        
    def fetch_events(self):
        """
        Used to finalize ui construction
        """
        note = osso.SystemNote(self.osso_context)
        result = note.system_note_infoprint("Fetching calendar entries..")
        
        self.connect_to_googbus_calendar()
        ret = self.calendar_iface.Login()
        
        if ret == googdefs.GOOGBUS_RET_OK:
            """
            Login ok
            """
            self.build_view()
        elif ret == googdefs.GOOGBUS_RET_NO_ACCOUNT:
            """
            User account missing
            """
            self.hildon_note("No account", "No user account configured.")
            dlg = UserAccountDlg(self.wnd)
            if dlg.run_dialog():
                if self.calendar_iface.Login() == googdefs.GOOGBUS_RET_OK:
                    self.build_view()
                else:
                    print "Tried login again and still something wrong.. quitting!"
                    gtk.main_quit()
            else:
                gtk.main_quit()
        else:
            """
            Invalid login or some other error
            """
            self.hildon_note("Login failed", "Login to Google account failed.\nCheck user account information.")
            
        
        return False
    
    
    def build_view(self):
        """
        Builds views with calendar entries listed
        """
        events, count = self.get_calendar_entries()
        event_box = self.create_event_box(events, count)
        self.scrolledwnd.add_with_viewport(event_box)
        self.wnd.show_all()
        
    
    def hildon_note(self, title, message):
        """
        Shows hildon note with OK button
        """
        dialog = hildon.Note ("information", (self.wnd, message, gtk.STOCK_DIALOG_INFO) )
        dialog.set_button_text("OK")
        dialog.run()
        dialog.destroy()


    def create_event_box(self, cal_entries, count):
        """
        Creates VBox that holds events
        """
        EVENT_TITLE_MARKUP = '<span foreground="gray">%s</span>'
        EVENT_DATE_MARKUP = '<span foreground="#000000"><small>%s</small></span>'
        EVENT_INFO_MARKUP = '<i>  %s-%s</i> <span foreground="#336699" >  %s</span>'
        
        self.box = gtk.VBox()
        self.box.set_spacing(5)
        
        if count == 0:
            """
            No events. 
            """
            no_events_lbl = gtk.Label()
            no_events_lbl.set_markup(EVENT_INFO_MARKUP % ("", "No coming events."))
            self.box.pack_start(no_events_lbl, False, False)
            self.box.show()
            return self.box

        previous_date = ""
        today = datetime.datetime.today()
        tomorrow = today + datetime.timedelta(days=1)
        
        first_event_passed = False
        
        for entry in cal_entries:
            start = datetime.datetime.fromtimestamp(entry[1]) #Event start time
            end = datetime.datetime.fromtimestamp(entry[2])   #Event end time
            
            sdate = start.strftime(self.LOCALE_DATE) #Start date str
            stime = start.strftime(self.LOCALE_TIME) #Start time str
            
            edate = end.strftime(self.LOCALE_DATE) #End date str
            etime = end.strftime(self.LOCALE_TIME) #End time str
            
            """
            Let's remove seconds if they are zero. They usually are :)
            """
            secs_pos = stime.rfind(":00")
            if secs_pos <> -1:
                stime = stime[:secs_pos] + stime[secs_pos+3:] 
            
            secs_pos = etime.rfind(":00")
            if secs_pos <> -1:
                etime = etime[:secs_pos] + etime[secs_pos+3:]
   
            if previous_date <> start.date():
                """
                Builds event title.
                
                Only display date title if date changes
                """                                
                lbl_title = gtk.Label()
                lbl_date  = gtk.Label()
                lbl_box   = gtk.HBox()
                                    
                if start.date() == today.date():
                    lbl_title.set_markup(EVENT_TITLE_MARKUP % ("Today"))
                elif start.date() == tomorrow.date():
                    lbl_title.set_markup(EVENT_TITLE_MARKUP % ("Tomorrow"))
                else:
                    lbl_title.set_markup(EVENT_TITLE_MARKUP % GoogbusCalendarApp.WEEKDAYS[start.weekday()])
                
                lbl_date.set_markup(EVENT_DATE_MARKUP % (sdate))

                lbl_title.set_alignment(0,0) #Align left
                lbl_date.set_alignment(1,0)  #Align right
                lbl_box.pack_start(lbl_title, False, False)
                lbl_box.pack_start(lbl_date, True, True)
 
                if first_event_passed:
                    """
                    First event passed, we can start putting separators
                    """
                    separator = gtk.HSeparator()
                    self.box.pack_start(separator, False, False)
                    
                self.box.pack_start(lbl_box, False, False)
                            
            previous_date = start.date()
            
            """
            Build event info
            """
            lbl_event = gtk.Label()
            lbl_event.set_markup(EVENT_INFO_MARKUP % (stime, etime, entry[0]))
            lbl_event.set_alignment(0,0)
            
            self.box.pack_start(lbl_event, False, False)
            
            first_event_passed = True 
            
        self.box.show()
        
        return self.box
        
        
    def add_event(self, widget, data = None):
        """
        Shows dialog for adding event to calendar
        
        Also toolbar button callback
        """
        dialog = AddNewEventDlg("Add new event")
        dialog.set_calendar_iface(self.calendar_iface)
        dialog.set_osso_context(self.osso_context)
       
        if dialog.run():
            self.refresh_events()
    
    
    def refresh_events(self, widget = None, data = None):
        """
        Refresh event list from Google
        """
        self.box.hide()
        self.box.destroy()
        self.fetch_events()
        
        
    def create_toolbar(self):
        """
        Creates toolbar
        """
        toolbar = gtk.Toolbar()

        btn_add = gtk.ToolButton (None, "Add event")
        btn_add.connect("clicked", self.add_event)
        toolbar.insert(btn_add, -1)
        
        btn_refresh = gtk.ToolButton (None, "Refresh")
        btn_refresh.connect("clicked", self.refresh_events)
        toolbar.insert(btn_refresh, -1)
        
        btn_add.show()
        btn_refresh.show()
        toolbar.show()
        
        
        self.wnd.add_toolbar(toolbar)
        
                
    def get_calendar_entries(self):
        """
        Fetches entries from Google calendar
        """
        return self.calendar_iface.ListEntriesFromToday()
    
    
    def connect_to_googbus_calendar(self):
        """
        Connects to Googbus
        """
        self.bus = dbus.SessionBus ()
        
        self.calendar_object = self.bus.get_object (googdefs.GOOGBUS_DBUS_SERVICE , 
                                                     googdefs.GOOGBUS_DBUS_CALENDAR_OBJECT)
        self.calendar_iface = dbus.Interface(self.calendar_object,
                                             googdefs.GOOGBUS_DBUS_CALENDAR_INTERFACE)
    
        
    def run(self):                
        self.wnd.show_all()
        gtk.main()

"""
Lets start!
"""
app = GoogbusCalendarApp()
app.run()

